package com.spzx.common.log.aspect;

import com.alibaba.fastjson2.JSON;
import com.spzx.common.log.annotation.PrintLog;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Arrays;

//切面类
@Aspect
@Component
@Slf4j
public class PrintLogAspect {
    //@annotation(printLog) 对使用printLog类型的注解的方法进行增强
    // 环绕通知执行时，可以将目标方法上的printLog注解对象传入到方法中使用
    @Around(value = "@annotation(printLog)")
    public Object around(ProceedingJoinPoint joinPoint , PrintLog printLog){

        try {
            //1、打印请求日志
            //获取请求对象(需要使用它获取请求报文中的数据)
            //SpringBoot提供了一个工具类 可以在任意的地方获取请求对象
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();

            // 打印访问的模块标题、请求路径、请求方式、请求参数..
            String title = printLog.title();
            boolean printParam = printLog.isPrintParam();
            String requestParams = printParam ?
                    ",请求参数："+ Arrays.toString(joinPoint.getArgs()) : "";
            log.info("{} 模块被访问了,请求方式:{} ，资源路径:{} "+requestParams,title,
                    request.getMethod() ,
                    request.getRequestURI());

            long start = System.currentTimeMillis();//记录目标方法开始执行的时间
            //执行目标方法得到结果
            Object result = joinPoint.proceed();

            //2、打印响应日志
            String resultStr = printLog.isPrintResult()?
                    ",响应结果:"+ JSON.toJSONString(result):"";
            // 打印访问的模块标题、响应结果、接口执行的时长
            log.info("{} 模块被访问了, 执行时长:{} s "+resultStr , title , (System.currentTimeMillis()-start)*1.0/1000 );


            return result;//返回目标方法执行的结果
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }



    }
}
